#ifndef	INC_VECTOR_H
#define	INC_VECTOR_H

#include <ostream>
#include <math.h>
/*********************************************/
namespace CVector
{
template<typename T>
class CVector
{
private:
		
	T	v[4];						// array of 4 elements
	
public:
	
	const T operator[]( const int& ) const;			// read only operator
	T& operator[]( const int& );				// access operator	
	void operator=( const CVector<T>& );			// assignment
	CVector<T> operator+=( const CVector<T>& );		// addition
	void operator*( const T& );				// multiplication by scalar
	void operator=( const Point3D& p );			// Data transistion from a Point3D struct
	CVector<T> operator-( const CVector<T>& v1 );		// Substraction
	void normalise();					// Nomalisation off the vector
	
	CVector(T&, T&, T&, T&);				// Construction with initialization
	CVector();						// Constructor
	CVector( const CVector<T>& );				// Copy Constructor
	~CVector();						// Destructor
};
/*********************************************/
template<typename T>
CVector<T>::CVector(T& x, T& y, T& z, T& w)
{
	v[0] = x;
	v[1] = y;
	v[2] = z;
	v[3] = w;
}
/*********************************************/
template<typename T>
CVector<T> CVector<T>::operator+=( const CVector<T>& vec )
{
	v[0] += vec.v[0];
	v[1] += vec.v[1];
	v[2] += vec.v[2];
}
/*********************************************/
template<typename T>
void CVector<T>::operator*( const T& scalar )
{
	v[0] = v[0] * scalar;
	v[1] = v[1] * scalar;
	v[2] = v[2] * scalar;
}
/*********************************************/
template<typename T>
const T CVector<T>::operator[]( const int& index ) const
{
	return( v[index] );
}
/*********************************************/
template<typename T>
T& CVector<T>::operator[]( const int& index )
{
	return( v[index] );
}
/*********************************************/
template<typename T>
CVector<T>::CVector()
{
	v[0] = 0;
	v[1] = 0;
	v[2] = 0;
	v[3] = 0;
}
/*********************************************/
template<typename T>
CVector<T>::~CVector<T>()
{
}
/*********************************************/
template<typename T>
void CVector<T>::operator=( const CVector<T>& vec )
{
	v[0] = vec.v[0];
	v[1] = vec.v[1];
	v[2] = vec.v[2];
	v[3] = vec.v[3];	
}
/*********************************************/
template<typename T>
CVector<T>::CVector( const CVector<T>& vec )
{
	v[0] = vec.v[0];
	v[1] = vec.v[1];
	v[2] = vec.v[2];
	v[3] = vec.v[3];
}
/*********************************************/
template<typename T>
void CVector<T>::operator=( const Point3D& p )
{
	fl32	x,y,z;
	p.getCoordinates( x,y,z );

	v[0] = x;
	v[1] = y;
	v[2] = z;
}
/*********************************************/
template<typename T>
CVector<T> CVector<T>::operator-( const CVector<T>& v1 )
{
	CVector<T>		sum;
	
	sum.v[0] = v[0] - v1[0];	
	sum.v[1] = v[1] - v1[1];
	sum.v[2] = v[2] - v1[2];
	sum.v[3] = v[3] - v1[3];
	
	return( sum );
}
/*********************************************/
template<typename T>
void CVector<T>::normalise()
{
	fl32 length = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3] );
	
	v[0] = v[0]/length;
	v[1] = v[1]/length;
	v[2] = v[2]/length;
	v[3] = v[3]/length;
}







/*********************************************/
//##### Non-member operations ( access through member operations )
/*********************************************/
template<typename T>
std::ostream& operator<<( std::ostream& ostr, const CVector<T>& vec)
{
	ostr << "[ " << vec[0] << " | " << vec[1] 
			<< " | " << vec[2] << " | " << vec[3] << " ]";
	return( ostr );
}
/*********************************************/
template<typename T>
CVector<T> operator*( const CVector<T>& v, const CVector<T>& vec )
{
	CVector<T>	cp;
		
	cp[0] = (v[1]*vec[2]) - (v[2]*vec[1]);
	cp[1] = (v[2]*vec[0]) - (v[0]*vec[2]);
	cp[2] = (v[0]*vec[1]) - (v[1]*vec[0]);
	
	return( cp );
}
/*********************************************/
template<typename T>
const T operator%( const CVector<T>& v, const CVector<T>& vec )
{
	return( v[0]*vec.v[0] + v[1]*vec.v[1] + v[2]*vec[2] );
}
/*********************************************/
template<typename T>
CVector<T> operator+( const CVector<T>& v1, const CVector<T>& v2 )
{
	CVector<T> sum;
	
	sum += v1;
	sum += v2;
	
	return( sum );
}
/*********************************************/
};		// namespace CVector
#endif //INC_VECTOR_H